
#import "ExtraCategories.h"




@implementation NSAffineTransform (RectMapping)


	/* set the NSAffineTransform so that it maps from a source
	rectangle to a destination rectangle. */
- (NSAffineTransform*)mapFrom:(NSRect) src to: (NSRect) dst {
	NSAffineTransformStruct at;
	at.m11 = (dst.size.width/src.size.width);
	at.m12 = 0.0;
	at.tX = dst.origin.x - at.m11*src.origin.x;
	at.m21 = 0.0;
	at.m22 = (dst.size.height/src.size.height);
	at.tY = dst.origin.y - at.m22*src.origin.y;
	[self setTransformStruct: at];
	return self;
}

	/* create a transform that proportionately scales bounds to a rectangle of height
	centered distance units above a particular point.   */
- (NSAffineTransform*)scaleBounds:(NSRect) bounds toHeight: (float) height centeredDistance:(float) distance abovePoint:(NSPoint) location {
	NSRect dst = bounds;
	float scale = (height / dst.size.height);
	dst.size.width *= scale;
	dst.size.height *= scale;
	dst.origin.x = location.x - dst.size.width/2.0;
	dst.origin.y = location.y + distance;
	return [self mapFrom:bounds to:dst];
}

	/* create a transform that proportionately scales bounds to a rectangle of height
	centered distance units above the origin.   */
- (NSAffineTransform*)scaleBounds:(NSRect) bounds toHeight: (float) height centeredAboveOrigin:(float) distance {
	return [self scaleBounds: bounds toHeight: height centeredDistance: distance abovePoint: NSMakePoint(0,0)];
}

@end





@implementation NSBezierPath (ShadowDrawing)


	/* fill a bezier path, but draw a shadow under it offset by the
	given angle (counter clockwise from the x-axis) and distance. */
- (void)fillWithShadowAtDegrees:(float) angle withDistance: (float) distance {
	float radians = angle*(3.141592/180.0);
	
		/* create a new shadow */
	NSShadow* theShadow = [[NSShadow alloc] init];
	
		/* offset the shadow by the indicated direction and distance */
	[theShadow setShadowOffset:NSMakeSize(cosf(radians)*distance, sinf(radians)*distance)];
	
		/* set other shadow parameters */
	[theShadow setShadowBlurRadius:3.0];
	[theShadow setShadowColor:[[NSColor blackColor] colorWithAlphaComponent:0.3]];

		/* save the graphics context */
	[NSGraphicsContext saveGraphicsState];
	
		/* use the shadow */
	[theShadow set];

		/* fill the NSBezierPath */
	[self fill];
	
		/* restore the graphics context */
	[NSGraphicsContext restoreGraphicsState];
	
		/* done with the shadow */
	[theShadow release];
}

@end




@implementation NSString (BezierConversions)

	
	/* convert a string into a NSBezierPath using the provided font. */
- (NSBezierPath*) bezierWithFont: (NSFont*) theFont {
		/* create the result */
	NSBezierPath *bezier = [NSBezierPath bezierPath];
		/* set up the layout and storage pieces */
	NSTextStorage *textStore = [[NSTextStorage alloc] initWithString: self];
	NSTextContainer *textContainer = [[NSTextContainer alloc] init];
	NSLayoutManager *myLayout = [[NSLayoutManager alloc] init];
		/* link them together */
	[myLayout addTextContainer: textContainer];
	[textStore addLayoutManager: myLayout];
		/* set the font */
	[textStore setFont: theFont];
		/* allocate storage for the glyphs */
	NSRange glyphRange = [myLayout glyphRangeForTextContainer:textContainer];
	NSGlyph *glyphArray = (NSGlyph*) malloc( sizeof(NSGlyph) * glyphRange.length );
	if ( glyphArray != NULL ) {
			/* retrive the glyphs */
		unsigned glyphCount = [myLayout getGlyphs: glyphArray range:glyphRange];	
			/* add the glyphs outlines to the NSBezierPath */
		[bezier moveToPoint:NSMakePoint(0.0, 0.0)];
		[bezier appendBezierPathWithGlyphs:glyphArray count:glyphCount inFont:theFont];
			/* done with the glyph array */
		free((void*) glyphArray);
	}
		/* clean up the layout and storage pieces */
	[textStore release];
	[textContainer release];
	[myLayout release];
		/* set some attributes of the bezier so it draws nicely */
	[bezier setLineJoinStyle:NSRoundLineJoinStyle];
	[bezier setLineCapStyle:NSRoundLineCapStyle];
	[bezier setLineWidth: 0.25];
		/* return the new curve */
	return bezier;
}


@end

